/****************************************Copyright (c)**************************************************
**                               深圳巨晶科技公司
**
**--------------File Info-------------------------------------------------------------------------------
* 文 件 名 : 文件名.h
* 作    者 : 作者名
* 版	本 ：
* 完成时间 : 年月日
* 描	述 ：
**------------------------------------------------------------------------------------------------------
* 修 改 人 ：
* 版	本 ：
* 修改时间 : 年月日
* 修改内容 : 
*********************************************************************************************************
*/
#include "I2C_driver.h"

/*
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
*											 私有宏(常量)定义区		private CONSTANTS
#define ...
enum {.,.,.}XXX;
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
*/
/*
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
*											  公有变量定义区		public VARIABLES
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
*/

/*
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
*											  私有变量定义区		private VARIABLES
static ...;
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
*/
#if USE_I2C_NUM != 0
//适应实时操作系统用的I2C驱动数据
sI2C_DRIVER		i2c_drive[USE_I2C_NUM];



#pragma region //--------------------中断回调函数------------------------
				  
/*******************************************************************************
* Description	  :	主发送完成回调函数
* Return		  :	None
*******************************************************************************/
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c/*指向I2C结构句柄*/)
{
	for (int i = 0; i < USE_I2C_NUM; i++) {
		if (hi2c == i2c_drive[i].phi2c) {
			osSemaphoreRelease(i2c_drive[i].DoneSemId);
			break;
		}
	}
}
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c/*指向I2C结构句柄*/)
{
	for (int i = 0; i < USE_I2C_NUM; i++) {
		if (hi2c == i2c_drive[i].phi2c) {
			osSemaphoreRelease(i2c_drive[i].DoneSemId);
			break;
		}
	}
}
/*******************************************************************************
* Description	  :	主接收完成回调函数
* Return		  :	None
*******************************************************************************/
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c/*指向I2C结构句柄*/)
{
	for (int i = 0; i < USE_I2C_NUM; i++) {
		if (hi2c == i2c_drive[i].phi2c) {
			osSemaphoreRelease(i2c_drive[i].DoneSemId);
			break;
		}
	}
}
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c/*指向I2C结构句柄*/)
{
	for (int i = 0; i < USE_I2C_NUM; i++) {
		if (hi2c == i2c_drive[i].phi2c) {
			osSemaphoreRelease(i2c_drive[i].DoneSemId);
			break;
		}
	}
}
/*
********************************************************************************
** 描    述 :	所有I2C出错中断回调函数都到这里，因此要判断是哪个I2C
** 返    回 :	无
********************************************************************************/
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c/*指向I2C结构句柄*/)
{
	for (int i = 0; i < USE_I2C_NUM; i++) {
		if (hi2c == i2c_drive[i].phi2c) {
			hi2c->ErrorCode = 255;
			osSemaphoreRelease(i2c_drive[i].DoneSemId);
			break;
		}
	}
//	hi2c->Instance->CR1 &= ~I2C_CR1_STOP;
}
#pragma endregion

#pragma region //===方法===
/*
********************************************************************************
** 描    述 :	注册I2C驱动变量并初始化
** 返    回 :	0:成功；1--重复初始化已经注册过了；-2--i2c_drive变量已经用完，需调整USE_I2C_NUM数据。
********************************************************************************/
int I2C_Init(sI2C_DRIVER         **pI2cDriver,         /*[out]指向指向I2C驱动结构的指针*/
             I2C_HandleTypeDef   *phi2c,               /*[IN]指向I2C句柄*/
             osSemaphoreId       DoneSemId)            /*[IN]I2C通讯完成信号量句柄或ID号*/
{
	for (int i=0; i<USE_I2C_NUM; i++){
		if (i2c_drive[i].phi2c == NULL) {
			i2c_drive[i].phi2c = phi2c;
			i2c_drive[i].DoneSemId = DoneSemId;
			*pI2cDriver = &i2c_drive[i];
			osSemaphoreWait(DoneSemId, 100);			//清除创建时默认生成的1个信号量
			return 0;
		}
		if (i2c_drive[i].phi2c == phi2c) {
			*pI2cDriver = &i2c_drive[i];
			return 1;
		}
	}
	return -2;
}

/*
********************************************************************************
** 描    述 :	通过I2C向外设器件写1个数据或命令
** 返    回 :	0:成功，-1--访问I2C故障，其它--设备无应答或其它总线错误
********************************************************************************/
int I2C_WriteCommand(sI2C_DRIVER *pI2cDriver/*指向I2C驱动句柄*/,
	unsigned char device_addr/*外设或终端地址*/,
	unsigned char command/*写入外设器件的命令*/)
{
	//S+device_addr+SA+command+SA+P
	if (pI2cDriver->phi2c->hdmatx == NULL) {
		if (HAL_I2C_Master_Transmit_IT(pI2cDriver->phi2c, device_addr, &command, 1) != HAL_OK)
			return -1;
	}
	else {
		if (HAL_I2C_Master_Transmit_DMA(pI2cDriver->phi2c, device_addr, &command, 1) != HAL_OK)
			return -1;
	}
	//等待发送完成或产生故障中断回调
	osSemaphoreWait(pI2cDriver->DoneSemId, osWaitForever);
	return pI2cDriver->phi2c->ErrorCode;
}

/*
********************************************************************************
** 描    述 :	通过I2C从外设器件读入len个数据
** 返    回 :	0:成功，-1--访问I2C故障，其它--见 HAL_I2C_ERROR_NONE 定义
********************************************************************************/
int I2C_ReadData(sI2C_DRIVER *pI2cDriver/*指向I2C驱动句柄*/,
	unsigned char device_addr/*器件地址*/,
	unsigned char *pData/*指向读入的数据存放处*/,
	unsigned short len/*读入外设器件寄存器连续地址下的字节数*/)
{
	//S+device_addr+SA+D1+MA+...+Dn+MN+P
	if (pI2cDriver->phi2c->hdmarx == NULL) {//->UseDMA == 0) {
		if (HAL_I2C_Master_Receive_IT(pI2cDriver->phi2c, device_addr, pData, len) != HAL_OK)
			return -1;
	} else {
		if (HAL_I2C_Master_Receive_DMA(pI2cDriver->phi2c, device_addr, pData, len) != HAL_OK)
			return -1;
	}
	//等待接收完成或产生故障中断回调
	osSemaphoreWait(pI2cDriver->DoneSemId, osWaitForever);
  return pI2cDriver->phi2c->ErrorCode;
}

/*
********************************************************************************
** 描    述 :	通过I2C向外设器件寄存器写数据
** 返    回 :	0:成功，-1--访问I2C故障，其它--设备无应答或其它总线错误
********************************************************************************/
int I2C_WriteRegister(sI2C_DRIVER *pI2cDriver/*指向I2C驱动句柄*/,
	unsigned char device_addr/*外设或终端地址*/,
	unsigned char reg_addr/*外设器件的寄存器地址*/,
	unsigned char *pData/*指向欲写入的数据*/,
	unsigned short len/*写入外设器件寄存器连续地址下的字节数*/)
{
	if (pI2cDriver->phi2c->hdmatx == NULL) {
		//写寄存器地址
		if (HAL_I2C_Master_Sequential_Transmit_IT(pI2cDriver->phi2c, device_addr, &reg_addr, 1, I2C_FIRST_FRAME) != HAL_OK)
			return -1;
		//等待发送完成或产生故障中断回调
		osSemaphoreWait(pI2cDriver->DoneSemId, osWaitForever);
		if (pI2cDriver->phi2c->ErrorCode != HAL_I2C_ERROR_NONE)
			return pI2cDriver->phi2c->ErrorCode;
	
		//开始大批量写数据
		if (HAL_I2C_Master_Sequential_Transmit_IT(pI2cDriver->phi2c, device_addr, pData, len, I2C_LAST_FRAME) != HAL_OK)
			return -1;
//		if (HAL_I2C_Mem_Write_IT(pI2cDriver->phi2c, device_addr, reg_addr, I2C_MEMADD_SIZE_8BIT, pData, len) != HAL_OK)
//			return -1;
	} else {
		//写寄存器地址
#ifdef USE_DMA_WrADDRandSTOP
		if (HAL_I2C_Master_Seq_Transmit_DMA(pI2cDriver->phi2c, device_addr, &reg_addr, 1, I2C_FIRST_FRAME) != HAL_OK)	//会发送STOP位，有的器件不支持！
			return -1;
		//等待发送完成或产生故障中断回调
		osSemaphoreWait(pI2cDriver->DoneSemId, osWaitForever);
		if (pI2cDriver->phi2c->ErrorCode != HAL_I2C_ERROR_NONE)
			return pI2cDriver->phi2c->ErrorCode;
	
		//开始大批量写数据
		if (HAL_I2C_Master_Seq_Transmit_DMA(pI2cDriver->phi2c, device_addr, pData, len, I2C_LAST_FRAME) != HAL_OK)
			return -1;
#else		
		//用下面方法代替上述2个函数方法，但效率差！在写寄存器地址期间比其低级的任务得不到响应。
		if (HAL_I2C_Mem_Write_DMA(pI2cDriver->phi2c, device_addr, reg_addr, I2C_MEMADD_SIZE_8BIT, pData, len) != HAL_OK)
			return -1;
#endif
	}
	//等待发送完成或产生故障中断回调
	osSemaphoreWait(pI2cDriver->DoneSemId, osWaitForever);
  return pI2cDriver->phi2c->ErrorCode;
}

/*
********************************************************************************
** 描    述 :	通过I2C从外设器件寄存器读数据。有的器件不支持使用DMA模式读写寄存器数据，
DMA模式会写入寄存器地址紧接着发停止位。解决办法1@不使用DMA模式2@不要定义USE_DMA_WrADDRandSTOP
即可，但效率稍差--分2步进行访问1先写寄存器地址期间比其低级的任务得不到响应2再用DMA读写数据
** 返    回 :	0:成功，-1--访问I2C故障，其它--设备无应答或其它总线错误
********************************************************************************/
int I2C_ReadRegister(sI2C_DRIVER *pI2cDriver/*指向I2C驱动句柄*/,
	unsigned char device_addr/*外设或终端地址*/,
	unsigned char reg_addr/*外设器件的寄存器地址*/,
	unsigned char *pData/*指向读入的数据存放处*/,
	unsigned short len/*读入外设器件寄存器连续地址下的字节数*/)
{
	if (pI2cDriver->phi2c->hdmarx == NULL) {
		//写寄存器地址
		if (HAL_I2C_Master_Sequential_Transmit_IT(pI2cDriver->phi2c, device_addr, &reg_addr, 1, I2C_FIRST_FRAME) != HAL_OK)
			return -1;
		//等待发送完成或产生故障中断回调
		osSemaphoreWait(pI2cDriver->DoneSemId, osWaitForever);
		if (pI2cDriver->phi2c->ErrorCode != HAL_I2C_ERROR_NONE)
			return pI2cDriver->phi2c->ErrorCode;

		//开始大批量读数据
		if (HAL_I2C_Master_Sequential_Receive_IT(pI2cDriver->phi2c, device_addr, pData, len, I2C_LAST_FRAME) != HAL_OK)
			return -1;
	} else {
#ifdef USE_DMA_WrADDRandSTOP
		//写寄存器地址
		if (HAL_I2C_Master_Seq_Transmit_DMA(pI2cDriver->phi2c, device_addr, &reg_addr, 1, I2C_FIRST_FRAME) != HAL_OK)	//会发送STOP位，有的器件不支持！
			return -1;
		//等待发送完成或产生故障中断回调
		osSemaphoreWait(pI2cDriver->DoneSemId, osWaitForever);
		if (pI2cDriver->phi2c->ErrorCode != HAL_I2C_ERROR_NONE)
			return pI2cDriver->phi2c->ErrorCode;

		//开始大批量读数据
		if (HAL_I2C_Master_Seq_Receive_DMA(pI2cDriver->phi2c, device_addr, pData, len, I2C_FIRST_AND_LAST_FRAME) != HAL_OK)
			return -1;
#else
		//用下面方法代替上述2个函数方法，但效率差！在写寄存器地址期间比其低级的任务得不到响应。
		if (HAL_I2C_Mem_Read_DMA(pI2cDriver->phi2c, device_addr, reg_addr, I2C_MEMADD_SIZE_8BIT, pData, len) != HAL_OK)
			return -1;
#endif
	}
	//等待接收完成或产生故障中断回调
	if (osSemaphoreWait(pI2cDriver->DoneSemId, 100) != osOK)
		return -1;
  return pI2cDriver->phi2c->ErrorCode;
}

#pragma endregion

/*
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
															结束
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
*/
#endif
